using System;
using System.Windows;
using System.Windows.Controls;
using WPFTemplateLib.WpfHelpers;

namespace WPFTemplateLib.Attached
{
	/*
	* 源码已托管：https://gitee.com/dlgcy/WPFTemplateLib
	* 版本：2025年5月15日
	*/

	/// <summary>
	/// [DLGCY][附加属性帮助类] 旋转转为位移（用于跟随旋转）(版本2)。
	/// </summary>
	/// <remarks>
	///	与版本1的区别：赋值旋转元素而不是旋转中心，旋转中心自动计算，且支持旋转中心本身的位移(Canvas 坐标变化)。（不确定会不会影响性能）
	/// </remarks>
	public class RotateToTranslateAttachedV2
	{
		#region [附加属性] 旋转中心（私有）
		private static Point GetOriginRotationCenter(DependencyObject obj)
		{
			return (Point)obj.GetValue(OriginRotationCenterProperty);
		}
		/// <summary>
		/// 旋转中心
		/// </summary>
		private static void SetOriginRotationCenter(DependencyObject obj, Point value)
		{
			obj.SetValue(OriginRotationCenterProperty, value);
		}
		/// <summary>
		/// [附加属性] 旋转中心
		/// </summary>
		public static readonly DependencyProperty OriginRotationCenterProperty =
			DependencyProperty.RegisterAttached("OriginRotationCenter", typeof(Point), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(new Point()));
		#endregion

		#region [附加属性] 旋转元素
		public static FrameworkElement GetRotationElement(DependencyObject obj)
		{
			return (FrameworkElement)obj.GetValue(RotationElementProperty);
		}
		/// <summary>
		/// 旋转元素
		/// </summary>
		public static void SetRotationElement(DependencyObject obj, FrameworkElement value)
		{
			obj.SetValue(RotationElementProperty, value);
		}
		/// <summary>
		/// [附加属性] 旋转元素
		/// </summary>
		public static readonly DependencyProperty RotationElementProperty =
			DependencyProperty.RegisterAttached("RotationElement", typeof(FrameworkElement), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(null, RotationElementChangedCallback));
		/// <summary>
		/// 旋转元素变化
		/// </summary>
		private static void RotationElementChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var element = d as FrameworkElement; //当前元素
			var rotateElement = e.NewValue as FrameworkElement; //旋转元素
			if(element == null || rotateElement == null)
				return;

			var elementTransformPoint = element.GetRenderTransformOriginPointInCanvas(out Point gapPoint);
			var rotateElementTransformPoint = rotateElement.GetRenderTransformOriginPointInCanvas(out _);
			var followPointRelative = new Point(elementTransformPoint.X - rotateElementTransformPoint.X, elementTransformPoint.Y - rotateElementTransformPoint.Y);

			SetOriginRotationCenter(d, rotateElementTransformPoint);
			SetGapPoint(d, gapPoint);
			SetFollowPointRelative(d, followPointRelative);

			UpdateFollowPointPosition(d);
		}

		#endregion

		#region [附加属性] 跟随点相对位置（私有）
		private static Point GetFollowPointRelative(DependencyObject obj)
		{
			return (Point)obj.GetValue(FollowPointRelativeProperty);
		}
		/// <summary>
		/// 跟随点相对位置（使用跟随元素的原点坐标减去旋转元素原点坐标）
		/// </summary>
		private static void SetFollowPointRelative(DependencyObject obj, Point value)
		{
			obj.SetValue(FollowPointRelativeProperty, value);
		}
		/// <summary>
		/// [附加属性] 跟随点相对位置
		/// </summary>
		public static readonly DependencyProperty FollowPointRelativeProperty =
			DependencyProperty.RegisterAttached("FollowPointRelative", typeof(Point), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(new Point()));
		#endregion

		#region [附加属性] 变化角度
		public static double GetChangedAngle(DependencyObject obj)
		{
			return (double)obj.GetValue(ChangedAngleProperty);
		}
		/// <summary>
		/// 变化角度
		/// </summary>
		public static void SetChangedAngle(DependencyObject obj, double value)
		{
			obj.SetValue(ChangedAngleProperty, value);
		}
		/// <summary>
		/// [附加属性] 变化角度
		/// </summary>
		public static readonly DependencyProperty ChangedAngleProperty =
			DependencyProperty.RegisterAttached("ChangedAngle", typeof(double), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(0d, ChangedAngleChangedCallback));
		/// <summary>
		/// 变化角度变化
		/// </summary>
		private static void ChangedAngleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var element = d as FrameworkElement;
			if(element == null)
				return;

			UpdateFollowPointPosition(element);
		}
		#endregion

		#region [附加属性] 距离（私有）
		private static Point GetGapPoint(DependencyObject obj)
		{
			return (Point)obj.GetValue(GapPointProperty);
		}
		/// <summary>
		/// 距离（跟随元素原点与左上角的坐标差）
		/// </summary>
		private static void SetGapPoint(DependencyObject obj, Point value)
		{
			obj.SetValue(GapPointProperty, value);
		}
		/// <summary>
		/// [附加属性] 距离
		/// </summary>
		public static readonly DependencyProperty GapPointProperty =
			DependencyProperty.RegisterAttached("GapPoint", typeof(Point), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(new Point()));
		#endregion

		#region [附加属性] 位置变化（Left）
		public static double GetPositionChangeLeft(DependencyObject obj)
		{
			return (double)obj.GetValue(PositionChangeLeftProperty);
		}
		/// <summary>
		/// 位置变化（Left）
		/// </summary>
		public static void SetPositionChangeLeft(DependencyObject obj, double value)
		{
			obj.SetValue(PositionChangeLeftProperty, value);
		}
		/// <summary>
		/// [附加属性] 位置变化（Left）
		/// </summary>
		public static readonly DependencyProperty PositionChangeLeftProperty =
			DependencyProperty.RegisterAttached("PositionChangeLeft", typeof(double), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(0d, PositionChangeLeftChangedCallback));
		/// <summary>
		/// 位置变化（Left）变化
		/// </summary>
		private static void PositionChangeLeftChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			UpdateFollowPointPosition(d);
		}
		#endregion

		#region [附加属性] 位置变化（Top）
		public static double GetPositionChangeTop(DependencyObject obj)
		{
			return (double)obj.GetValue(PositionChangeTopProperty);
		}
		/// <summary>
		/// 位置变化（Top）
		/// </summary>
		public static void SetPositionChangeTop(DependencyObject obj, double value)
		{
			obj.SetValue(PositionChangeTopProperty, value);
		}
		/// <summary>
		/// [附加属性] 位置变化（Top）
		/// </summary>
		public static readonly DependencyProperty PositionChangeTopProperty =
			DependencyProperty.RegisterAttached("PositionChangeTop", typeof(double), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(0d, PositionChangeTopChangedCallback));
		/// <summary>
		/// 位置变化（Top）变化
		/// </summary>
		private static void PositionChangeTopChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			UpdateFollowPointPosition(d);
		}
		#endregion

		#region [附加属性] 每角度导致的远离值（默认0）
		public static double GetAwayDistancePerDegree(DependencyObject obj)
		{
			return (double)obj.GetValue(AwayDistancePerDegreeProperty);
		}
		/// <summary>
		/// 设置 每角度导致的远离值（默认0）
		/// </summary>
		public static void SetAwayDistancePerDegree(DependencyObject obj, double value)
		{
			obj.SetValue(AwayDistancePerDegreeProperty, value);
		}
		/// <summary>
		/// [附加属性] 每角度导致的远离值（默认0）
		/// </summary>
		public static readonly DependencyProperty AwayDistancePerDegreeProperty =
			DependencyProperty.RegisterAttached("AwayDistancePerDegree", typeof(double), typeof(RotateToTranslateAttachedV2), new PropertyMetadata(0d, (d, _) => UpdateFollowPointPosition(d)));
		#endregion

		/// <summary>
		/// 更新位置
		/// </summary>
		private static void UpdateFollowPointPosition(DependencyObject d)
		{
			var element = d as FrameworkElement;
			if(element == null)
				return;

			var angle = GetChangedAngle(d);
			//var rotationCenter = GetOriginRotationCenter(d);
			var rotateElement = GetRotationElement(d);
			if(rotateElement == null)
			{
				return; //此时应该是触发时机不对，可忽略
			}

			var rotationCenter = rotateElement.GetRenderTransformOriginPointInCanvas(out _);
			var rotationPointRelative = GetFollowPointRelative(d);
			var gapPoint = GetGapPoint(d);
			var awayDistancePerDegree = GetAwayDistancePerDegree(d);

			//解释：https://n.cn/share/r1/642f9dfa07bd41a49257903dffd78b7d?from=web

			var sin = Math.Sin(angle * Math.PI / 180);
			var cos = Math.Cos(angle * Math.PI / 180);

			//旋转变换产生的结果
			var xRot = rotationPointRelative.X * cos - rotationPointRelative.Y * sin;
			var yRot = rotationPointRelative.X * sin + rotationPointRelative.Y * cos;

			//如果有远离值，则需要计算新的坐标
			if(awayDistancePerDegree != 0)
			{
				//使用勾股定理计算旋转点与旋转中心的原始距离 originalDistance，作为基准半径。
				double originalDistance = Math.Sqrt(
					rotationPointRelative.X * rotationPointRelative.X +
					rotationPointRelative.Y * rotationPointRelative.Y
				);

				//根据旋转角度 angle 和参数 awayDistancePerDegree 计算总远离距离 scaledDistance。
				double scaledDistance = originalDistance + awayDistancePerDegree * angle;

				// 避免除以零并缩放坐标 
				if(originalDistance > 0)
				{
					double scale = scaledDistance / originalDistance;
					//通过缩放因子 scale 将旋转后的坐标按比例放大，实现沿旋转方向远离的效果。
					xRot *= scale;
					yRot *= scale;
				}
			}

			// 计算最终坐标 
			var newLeft = rotationCenter.X + xRot;
			var newTop = rotationCenter.Y + yRot;

			//转换为 Canvas 坐标
			newLeft = Math.Round(newLeft - gapPoint.X, 1);
			newTop = Math.Round(newTop - gapPoint.Y, 1);
			Canvas.SetLeft(element, newLeft);
			Canvas.SetTop(element, newTop);
		}
	}
}
